#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "dlist.h"
#include "sys_cfg_tok.h"
#include "sys_cfg.h"


#define KEY_VALUE_MAX_LENGTH 64
#define CFG_LINE_MAX_LENGTH 512

struct SubKey {
    int line_number;
    char key[KEY_VALUE_MAX_LENGTH];
    char value[KEY_VALUE_MAX_LENGTH];
};

struct MainKey {
    char* key_name; 
    int line_number;
    DList* sub_key;
};

struct SysConfig {
    DList* main_key;
    struct MainKey* cur_main;
    DList* cfg_line;
};

static struct MainKey* sys_cfg_main_key_create();
static struct SubKey* sys_cfg_sub_key_create(const char* k, const char* v, int line_number);
static void sys_cfg_sub_key_destory(void* data);

DList* sys_cfg_get_sub_key_list(struct MainKey* mk)
{
    if(mk != NULL)
    {
        return mk->sub_key;
    }

    return NULL;
}

int sys_cfg_main_key_cmp_func(void* left, void* right)
{
    return_if_fail_val(left != NULL && right != NULL, -1);
    char* key_name = (char *)left;
    struct MainKey* mk = (struct MainKey *)right;
    //printf("%s %s %s\n", __func__, key_name, mk->key_name);
    return strncmp(key_name, mk->key_name, KEY_VALUE_MAX_LENGTH);
}

char* sys_cfg_sub_key_get_key(struct SubKey* sub)
{
    if(sub != NULL) 
    {
        return sub->key;
    }
    
    return NULL;
}

char* sys_cfg_sub_key_get_value(struct SubKey* sub)
{
    if(sub != NULL)
    {
        return sub->value;
    }

    return NULL;
}

Ret sys_cfg_patch_main_key(struct SysConfig* thiz, const char* dst_mk_str, const char* src_mk_str)
{
    struct MainKey* dst_mk = sys_cfg_get_main_key(thiz, dst_mk_str);
    struct MainKey* src_mk = sys_cfg_get_main_key(thiz, src_mk_str);
   
    return_if_fail_val(dst_mk != NULL && src_mk != NULL, RET_ERROR);
    
    struct SubKey* src_sk = NULL;
    struct SubKey* dst_sk = NULL;
    int i, j;
    for(i = 0; i < dlist_get_length(src_mk->sub_key); i++)
    {
        dlist_get_data_by_index(src_mk->sub_key, i, (void **)&src_sk);
        for(j = 0; j < dlist_get_length(dst_mk->sub_key); j++)
        {
            dlist_get_data_by_index(dst_mk->sub_key, j, (void **)&dst_sk);
            if(dst_sk != NULL && src_sk != NULL)
            {
                if(!strncmp(dst_sk->key, src_sk->key, KEY_VALUE_MAX_LENGTH)){
                    //printf("%s patch %s [%s -> %s ] \n", __func__, dst_sk->key, src_sk->value, dst_sk->value);
                    memset(dst_sk->value, 0, KEY_VALUE_MAX_LENGTH);
                    memcpy(dst_sk->value, src_sk->value, KEY_VALUE_MAX_LENGTH);
                    break;
                } 
            }
        }
    }

    return RET_OK;
}

Ret sys_cfg_delete_main_key(struct SysConfig* thiz, const char* key_name)
{
    int index = 0;
    int ret = RET_OK;
    struct MainKey* mk;
    if((mk = dlist_find_by_data(thiz->main_key, (void *)key_name, sys_cfg_main_key_cmp_func, &index)) != NULL) {
        cfg_line_delete_by_line_number(thiz->cfg_line, mk->line_number);

        dlist_destroy(mk->sub_key);
        printf("%s %p %d\n", __func__, thiz->main_key, index);
        ret = dlist_delete(thiz->main_key, index);
    }

    return ret;
}

struct MainKey* sys_cfg_get_main_key(struct SysConfig* thiz, const char* key_name)
{
    return_if_fail_val(thiz != NULL && key_name != NULL, NULL);
    return (struct MainKey *)dlist_find_by_data(thiz->main_key, (void *)key_name, sys_cfg_main_key_cmp_func, NULL);
}

struct SubKey* sys_cfg_sub_key_create_from_str(int line_number, char* line)
{
    char* key = line;
    char* value = strchr(line, '=');
    char* end = NULL;
    if(value != NULL)
    {
        /* key */
        while(!isblank(*line) && !isspace(*line))
        {
            line++;
            if(*line == '=')
            {
                break;
            }
        }
        *line = '\0';
        
        value++;
        /* value */
        while(isspace(*value) || *value == '"')
        {
            value++;
        }
        end = value;
        while(!isspace(*end) && *end != '"')
        {
            end++;
        }
        *end = '\0';
        //printf("%d orig_line:%s\nkey:%s value:%s", line_number, line, key, value);
        return sys_cfg_sub_key_create(key, value, line_number);
    }

    return NULL;
}

static struct SubKey* sys_cfg_sub_key_create(const char* k, const char* v, int line_number)
{
    struct SubKey* sk = (struct SubKey *)calloc(1, sizeof(struct SubKey));
    return_if_fail_val(sk != NULL, NULL);
   
    sk->line_number = line_number;
    strncpy(sk->key, k, KEY_VALUE_MAX_LENGTH - 1);
    strncpy(sk->value, v, KEY_VALUE_MAX_LENGTH - 1);

    return sk;
}


Ret sys_cfg_append_sub_key(struct SysConfig* thiz, struct SubKey* sk)
{
    return_if_fail_val(thiz != NULL && thiz->cur_main != NULL && sk != NULL, RET_PARAM_ERROR);
    dlist_append(thiz->cur_main->sub_key, sk);
    
    return RET_OK;
}

Ret sys_cfg_append_main_key(struct SysConfig* thiz, struct MainKey* mk)
{
    return_if_fail_val(thiz != NULL && mk != NULL, RET_PARAM_ERROR);
    dlist_append(thiz->main_key, mk);
    thiz->cur_main = mk;

    return RET_OK;
}

struct MainKey* sys_cfg_main_key_create_from_str(int line_number, char* line)
{
    return_if_fail_val(*line == '[', NULL);

    struct MainKey* mk = sys_cfg_main_key_create();
    return_if_fail_val(mk != NULL, NULL);
 
    char* end = strchr(line, ']');
    if(end != NULL) 
    {
        *end = '\0';
        mk->key_name = strdup(line + 1); //skip '['
        mk->line_number = line_number;
    }
    mk->sub_key = dlist_create(sys_cfg_sub_key_destory);

    return mk;
   
}

static struct MainKey* sys_cfg_main_key_create()
{
    struct MainKey* mk = (struct MainKey *)malloc(sizeof(struct MainKey));
    return_if_fail_val(mk != NULL, NULL);

    mk->key_name = NULL;
    mk->sub_key = dlist_create(sys_cfg_sub_key_destory);

    return mk;
}

static void sys_cfg_sub_key_destory(void* data)
{
   struct SubKey* sub_key = (struct SubKey *)data;
   if(sub_key != NULL) 
   {
       //printf("subkey addr:%p\n", sub_key);
       //printf("line number:%d key:%s value:%s\n", sub_key->line_number, sub_key->key, sub_key->value);
       free(sub_key);
       sub_key = NULL;
   }
}

static void sys_cfg_main_key_destroy(void* data)
{
    struct MainKey* mk = (struct MainKey *)data;
    if(mk != NULL) {
        //printf("main key:%p key name:%s\n", mk, mk->key_name);
        if(mk->key_name != NULL) 
        {
            free(mk->key_name);
            mk->key_name = NULL;
        }
        if(mk->sub_key != NULL) 
        {
            dlist_destroy(mk->sub_key);
            mk->sub_key = NULL;
        }
        free(mk);
        mk = NULL;
    }
}

void sys_cfg_destroy(struct SysConfig* thiz)
{
    if(thiz != NULL) 
    {
        dlist_destroy(thiz->main_key);
        free(thiz);
        thiz = NULL;
    }
}

static void sys_cfg_sub_key_dump(void *ctx, void *data)
{
    struct SubKey* sk = (struct SubKey *)data;
    printf("%s=%s\n", sk->key, sk->value);
    //printf("at line number:%d\n", sk->line_number);
}

static void sys_cfg_main_key_dump(void *ctx, void *data)
{
    struct MainKey* mk = (struct MainKey *)data;
    printf("[%s]\n", mk->key_name);
    //printf("line number%d\n", mk->line_number);
    dlist_foreach(mk->sub_key, sys_cfg_sub_key_dump, NULL);
    //printf("\n\n\n");
}

void sys_cfg_dump(struct SysConfig* thiz, char* file_path)
{
    //printf("=================sys config data struct dump start=======================");
    //printf("main key count: %d\n", dlist_get_length(thiz->main_key));
    dlist_foreach(thiz->main_key, sys_cfg_main_key_dump, NULL);
    //printf("================================ending line==============================");
}

struct SysConfig* sys_cfg_create()
{
    struct SysConfig* thiz = (struct SysConfig *)malloc(sizeof(struct SysConfig));
    return_if_fail_val(thiz != NULL, NULL);

    thiz->main_key = dlist_create(sys_cfg_main_key_destroy);

    return thiz;
}
